////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quick Reference                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Library Version -------------------------------------------------------------------------------------------------------------
//      Major Version: WN_LIBRARIES_VERSION / 100000
//      Minor Version: WN_LIBRARIES_VERSION / 100 % 1000
//      Patch Level:   WN_LIBRARIES_VERSION % 100

// Calling Conventions (All of the following)-----------------------------------------------------------------------------------
//      __WN_CDECL_BEGIN / __WN_CDECL_END
//      __WN_STDCALL_BEGIN / __WN_STDCALL_END
//      __WN_FASTCALL_BEGIN / __WN_FASTCALL_END

// Keyword (All of the following) ----------------------------------------------------------------------------------------------
//      __WN_INLINE
//      __WN_RESTRICT

// Properties (All of the following) -------------------------------------------------------------------------------------------
//      __WN_NO_INLINE
//      __WN_THREAD_LOCAL
//      __WN_ALIGNMENT

// Compiler (Only 1 of the following) ------------------------------------------------------------------------------------------
//      _WN_MSVC
//      _WN_GNUC
//      
// Platform (Only 1 of the following) ------------------------------------------------------------------------------------------
//      _WN_WINDOWS - Microsoft Windows
//      _WN_LINUX   - Linux
//      
// Architecture (Only 1 of the following) --------------------------------------------------------------------------------------
//      _WN_X86 - Defined for all x86 based architectures (i.e. x86, x86-64, etc.)
//      _WN_ARMV5
//      _WN_ARMV7
//      _WN_MIPS
//      _WN_PPC

// Processor Bit Width (Only 1 of the following) --------------------------------------------------------------------------------------
//      _WN_32_BIT
//      _WN_64_BIT

// Endianess (Only 1 of the following) -----------------------------------------------------------------------------------------
//      _WN_ENDIAN_LITTLE
//      _WN_ENDIAN_BIG
//      _WN_ENDIAN_UNKNOWN - Requires runtime check due to Bi-endian architecture

// Language ---------------------------------------------------------------------
//      _WN_CPLUSPLUS

// Character Set ---------------------------------------------------------------------------------------------------------------
//      _WN_UNICODE

// Debug -----------------------------------------------------------------------------------------------------------------------
//      _WN_DEBUG

// Types (All of the following) ------------------------------------------------------------------------------------------------
//      WN_VOID
//      WN_BYTE
//      WN_BOOL
//      WN_CHAR
//      WN_WCHAR
//      WN_INT8
//      WN_INT16
//      WN_INT32
//      WN_INT64
//      WN_UINT8
//      WN_UINT16
//      WN_UINT32
//      WN_UINT64
//      WN_FLOAT32
//      WN_FLOAT64
//      WN_POINTER
//      WN_SIZE_T
//      WN_ATOM_T

// Values (All of the following) -----------------------------------------------------------------------------------------------
//      WN_TRUE
//      WN_FALSE
//      WN_NULL

// Miscellaneous (All of the following) ----------------------------------------------------------------------------------------
//      WN_CDECL_FUNCTION_TYPEDEF
//      WN_STDCALL_FUNCTION_TYPEDEF
//      WN_FASTCALL_FUNCTION_TYPEDEF
//      WN_SYSCALL_FUNCTION_TYPEDEF

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_PLATFORM_H__
#define __WN_PLATFORM_H__

#ifdef __cplusplus
    #define _WN_CPLUSPLUS __cplusplus
#endif

#ifdef _HAS_EXCEPTIONS
    #undef _HAS_EXCEPTIONS
#endif

#define _HAS_EXCEPTIONS 0

#if (defined DEBUG || defined _DEBUG) && !defined NDEBUG
    #define _WN_DEBUG
#endif

#if defined UNICODE || defined _UNICODE
    #define _WN_UNICODE
#endif

#ifdef _MSC_VER // Microsoft Visual C++
    #if _MSC_VER < 1500
        #error "Compiler not supported: MSVC 9.0 (Visual Studio 2008) or higher must be used"
    #endif

    #if _MSC_VER < 1500
        #define _WN_MSVC (_MSC_VER * 100000)
    #else
        #define _WN_MSVC _MSC_FULL_VER
    #endif

    #define __WN_INLINE __forceinline
    #define __WN_RESTRICT __restrict

    #define __WN_NO_INLINE __declspec(noinline)
    #define __WN_THREAD_LOCAL __declspec(thread)
    #define __WN_ALIGNMENT(_a) __declspec(align(_a))

    #define WN_CDECL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (__cdecl *_name)(__VA_ARGS__)
    #define WN_STDCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (__stdcall *_name)(__VA_ARGS__)
    #define WN_FASTCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (__fastcall *_name)(__VA_ARGS__)

    #if defined _WIN32 || defined _WIN64
        #define _WN_WINDOWS

        // Set Windows version to Windows XP
        #define WINVER 0x0501
        #define _WIN32_WINNT 0x0501

        // This is defined so that other libraries (that define min and max functions) do not explode (thanks Windows)
        #define NOMINMAX

        #define _CRT_SECURE_NO_WARNINGS

        #pragma warning(disable: 4275)    // Non dll-interface class used as base for dll-interface class
        #pragma warning(disable: 4996)
        #pragma warning(disable: 4530)

        #include <windows.h>

        #define WN_SYSCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (WINAPI *_name)(__VA_ARGS__)
    #endif

    #if defined _M_X64 || defined _M_AMD64
        #define _WN_X86
        #define _WN_64_BIT

        #if _MSC_VER > 1400
            // For some reason this isn't defined at editing time just at compile time.  Define it so intellisense doesn't complain
            #ifndef _M_AMD64
                #define _M_AMD64
            #endif
        #endif

        #define _WN_ATOM_T_OVERRIDE

        typedef __int64 WN_ATOM_T;
    #elif defined _M_IX86
        #define _WN_X86
        #define _WN_32_BIT

        #define __WN_CDECL_BEGIN __cdecl
        #define __WN_CDECL_END

        #define __WN_STDCALL_BEGIN __stdcall
        #define __WN_STDCALL_END

        #define __WN_FASTCALL_BEGIN __fastcall
        #define __WN_FASTCALL_END
    #endif

    typedef unsigned __int8 WN_BYTE;

    typedef __int8 WN_INT8;
    typedef __int16 WN_INT16;
    typedef __int32 WN_INT32;
    typedef __int64 WN_INT64;

    typedef unsigned __int8 WN_UINT8;
    typedef unsigned __int16 WN_UINT16;
    typedef unsigned __int32 WN_UINT32;
    typedef unsigned __int64 WN_UINT64;

    #define _WN_WCHAR_OVERRIDE
    
    typedef __wchar_t WN_WCHAR;

    #if _MSC_VER >= 1600 || (defined _MSC_EXTENSIONS && defined _NATIVE_NULLPTR_SUPPORTED)
        #define WN_NULL __nullptr
    #endif

    #if _MSC_VER >= 1600
        #define _WN_HAS_NATIVE_STATIC_ASSERT
    #endif
#elif defined __GNUC__ // GNU C
    #ifdef __GNUC_PATCHLEVEL__
        #define _WN_GNUC (__GNUC__ * 100000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
    #else
        #define _WN_GNUC (__GNUC__ * 100000 + __GNUC_MINOR__ * 100)
    #endif

    #define __WN_INLINE __inline__
    #define __WN_RESTRICT __restrict__
    #define __WN_THREAD_LOCAL __thread

    #define __WN_NO_INLINE __attribute__(noinline)
    #define __WN_ALIGNMENT(_a) __attribute__(aligned(_a))

    #define WN_CDECL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (*_name)(__VA_ARGS__) __attribute__((cdecl))
    #define WN_STDCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (*_name)(__VA_ARGS__) __attribute__((stdcall))
    #define WN_FASTCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (*_name)(__VA_ARGS__) __attribute__((fastcall))

    #if defined linux || defined __linux || defined __linux__
        #define _WN_LINUX

        #define WN_SYSCALL_FUNCTION_TYPEDEF(_name, _return, ...) typedef _return (*_name)(__VA_ARGS__) __attribute__((cdecl))
    #endif

    #if defined __x86_64 || defined __x86_64__ || defined __amd64 || defined __amd64__
        #define _WN_X86
        #define _WN_64_BIT
    #elif defined i386 || defined __i386__
        #define _WN_X86
        #define _WN_32_BIT

        #define __WN_CDECL_BEGIN
        #define __WN_CDECL_END __attribute__((cdecl))

        #define __WN_STDCALL_BEGIN
        #define __WN_STDCALL_END __attribute__((stdcall))

        #define __WN_FASTCALL_BEGIN
        #define __WN_FASTCALL_END __attribute__((fastcall))
    #elif defined arm || defined __arm__
        #if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
            #define _WN_ARMV7
        #elif defined __ARM_ARCH_5__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__
            #define _WN_ARMV5
        #endif

        #define _WN_32_BIT
    #elif defined mips || defined __mips__
        #define _WN_MIPS
        #define _WN_32_BIT
    #elif defined __powerpc64 || defined __powerpc64__ || defined __POWERPC64__ || defined __ppc64__
        #define _WN_PPC
        #define _WN_64_BIT
    #elif defined __powerpc || defined __powerpc__ || defined __POWERPC__ || defined __ppc__
        #define _WN_PPC
        #define _WN_32_BIT
    #endif

    #ifdef __BIG_ENDIAN__
        #define _WN_ENDIAN_BIG
    #elif defined __LITTLE_ENDIAN__
        #define _WN_ENDIAN_LITTLE
    #else
        #define _WN_ENDIAN_UNKNOWN
    #endif

    #include <stdint.h>
    #include <stddef.h>

    typedef uint8_t WN_BYTE;

    typedef int8_t WN_INT8;
    typedef int16_t WN_INT16;
    typedef int32_t WN_INT32;
    typedef int64_t WN_INT64;

    typedef uint8_t WN_UINT8;
    typedef uint16_t WN_UINT16;
    typedef uint32_t WN_UINT32;
    typedef uint64_t WN_UINT64;

    #ifndef _WN_CPLUSPLUS
        #if __STDC_VERSION__ >= 199901L
            #include <stdbool.h>

            #define _WN_BOOL_OVERRIDE

            typedef bool WN_BOOL;

            #define WN_TRUE true
            #define WN_FALSE false
        #endif
    #endif

    #ifdef __GXX_EXPERIMENTAL_CXX0X__
        #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)
            #define WN_NULL nullptr
        #endif

        #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
            #define _WN_HAS_NATIVE_STATIC_ASSERT
        #endif
    #endif

    #if defined __GNUG__ && !defined WN_NULL
        #define WN_NULL __null
    #endif
#else
    #error "Compiler not supported"
#endif

typedef void WN_VOID;

typedef char WN_CHAR;

typedef float WN_FLOAT32;
typedef double WN_FLOAT64;

typedef size_t WN_SIZE_T;

typedef WN_BYTE* WN_POINTER;

#ifndef _WN_BOOL_OVERRIDE
    #ifdef _WN_CPLUSPLUS
        typedef bool WN_BOOL;

        #define WN_TRUE true
        #define WN_FALSE false
    #else
        typedef WN_UINT8 WN_BOOL;

        #define WN_TRUE 1
        #define WN_FALSE 0
    #endif
#else
    #undef _WN_BOOL_OVERRIDE
#endif

#ifndef _WN_WCHAR_OVERRIDE
    typedef wchar_t WN_WCHAR;
#else
    #undef _WN_WCHAR_OVERRIDE
#endif

#ifndef _WN_ATOM_T_OVERRIDE
    #ifdef _WN_64_BIT
        typedef long long WN_ATOM_T;
    #elif defined _WN_32_BIT
        typedef long int WN_ATOM_T;
    #endif
#else
    #undef _WN_ATOM_T_OVERRIDE
#endif

#ifndef WN_NULL
    #ifdef _WN_CPLUSPLUS
        #if _WN_CPLUSPLUS >= 201103L
            #define WN_NULL nullptr
        #else
            const
            class {
            public:
                template<class T>
                operator T*() const { return 0; }
                template<class C, class T>
                operator T C::*() const { return 0; }

            private:
                void operator&() const;
            } __WNNullPtr = {};

            #define WN_NULL __WNNullPtr
        #endif
    #else
        #define WN_NULL NULL
    #endif
#endif

#ifdef _WN_X86
    #ifndef _WN_ENDIAN_LITTLE
        #define _WN_ENDIAN_LITTLE
    #endif
#endif

#ifdef _WN_PPC
    #ifndef _WN_ENDIAN_BIG
        #define _WN_ENDIAN_BIG
    #endif
#endif

#if !defined _WN_ENDIAN_LITTLE && !defined _WN_ENDIAN_BIG
    #ifndef _WN_ENDIAN_UNKNOWN
        #define _WN_ENDIAN_UNKNOWN
    #endif
#else
    #ifdef _WN_ENDIAN_UNKNOWN
        #undef _WN_ENDIAN_UNKNOWN
    #endif
#endif

#ifndef __WN_CDECL_BEGIN
    #define __WN_CDECL_BEGIN
#endif

#ifndef __WN_CDECL_END
    #define __WN_CDECL_END
#endif

#ifndef __WN_STDCALL_BEGIN
    #define __WN_STDCALL_BEGIN
#endif

#ifndef __WN_STDCALL_END
    #define __WN_STDCALL_END
#endif

#ifndef __WN_FASTCALL_BEGIN
    #define __WN_FASTCALL_BEGIN
#endif

#ifndef __WN_FASTCALL_END
    #define __WN_FASTCALL_END
#endif
#define WN_LIBRARIES_VERSION 10000 // 0.1.0

#endif // __WN_PLATFORM_H__